package algorithms;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;

import algorithms.models.FeatureBag;
import algorithms.models.QueryTagsModel;

import edu.uci.ics.jung.algorithms.scoring.PageRank;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import puppy.eval.logloaders.FeaturesLoader;
import puppy.graph.AgeAggregator;

import puppy.graph.CreateGraphDirected;
import puppy.graph.CreateLM;
import puppy.graph.CreateUnigrams;
import puppy.graph.DeliciousEdge;
import puppy.graph.DeliciousEdgeSimple;
import puppy.graph.DeliciousEdgeTransformer;
import puppy.graph.DeliciousNode;
import puppy.graph.DeliciousNodeTransformer;
import puppy.graph.GraphExtractor;

import util.evaluation.QueryTag;
import util.hashing.*;
import util.ranker.RankingService;

public class TagSimilarity {

	public CreateGraphDirected graph = null;
	CreateLM lm = null; 
	double query_total=0;
	

	AgeAggregator agg=null;
	Hashtable<String, ArrayList<String>> queries_todo=null;
	QueryTagsModel querytags=null;
	CreateUnigrams unigrams = null;
	private int query_threshold_freq;
	
	public TagSimilarity(String graph,String co_occur, String query_tags,String features, HashSet<String>ages) {
	
		
	
		queries_todo = FeaturesLoader.loadQueryTagsFeatures(features);
		initLM(co_occur);
		this.agg=new AgeAggregator(ages);
		unigrams= new CreateUnigrams(agg,graph);
		HashSet<String>queries=init_queries_to_eval(queries_todo);
		 querytags = new QueryTagsModel(query_tags, queries,1);
	
	}
	
	
	private HashSet<String> init_queries_to_eval(
			Hashtable<String, ArrayList<String>> queries_todo2) {
		// TODO Auto-generated method stub
		HashSet<String>queries= new HashSet<String>();
		
		Enumeration<String> keys = queries_todo2.keys();
		while(keys.hasMoreElements()){
			
			
			String query = keys.nextElement();
			queries.add(query);
		}
		return queries;
	}


	public void initLM(String path){
		if(path==null) return;
		
		lm = new CreateLM();
		lm.initLM(path);
	}
	


	public void print_tag_similarity_features() {

		Enumeration<String> queries = queries_todo.keys();
		while (queries.hasMoreElements()) {
			String query = queries.nextElement();
			ArrayList<String> sugg = queries_todo.get(query);
			ArrayList<QueryTag> query_model = querytags.getQueries().get(query);
			Hashtable<String, Float> query_ratios = calculateQueryRatios(query_model);
			for (int i = 0; i < sugg.size(); i++) {

				String tag = sugg.get(i);

				// join probability
				double lm_value = calcualteLM(query_ratios, tag);
				double lm_valueAdults = calcualteLMAdults(query_ratios, tag);

				System.out.println(query + "\t" + tag + "\tlm_value\t"
						+ lm_value);
				
				System.out.println(query + "\t" + tag + "\tlm_value_adults\t"
						+ lm_valueAdults);
				// google distance
				double google = calcualteGoogleDistance(query_ratios, tag);

				System.out.println(query + "\t" + tag + "\tgoogle\t" + google);
				
				double googleA = calcualteGoogleDistanceAdults(query_ratios, tag);

				System.out.println(query + "\t" + tag + "\tgoogle_adults\t" + googleA);
				double ratio =googleA/google;
				if(Double.isNaN(ratio)) ratio=0;
				System.out.println(query + "\t" + tag + "\tgoogle_ratio\t" + ratio);
				
				// jaccard

				double jaccard = calcualteJaccardDistance(query_ratios, tag);

				System.out
						.println(query + "\t" + tag + "\tjaccard\t" + jaccard);
				
				
				double children_prob= calculateChildrenProb(tag);
				double children_distance= calculateChildrenDistance(tag);
				
				System.out.println(query + "\t" + tag + "\tgoogle_kids\t" + children_distance);
				
				System.out.println(query + "\t" + tag + "\tprob_kids\t" + children_prob);

			}

		}
	}

	
	

	
	private double calcualteLM(Hashtable<String, Float> query_ratios, String tag) {
		// TODO Auto-generated method stub
		
		
		Enumeration<String> keys = query_ratios.keys();
		
		double similarity=0;
		while(keys.hasMoreElements()){
			
			String key=keys.nextElement();
			float ratio=query_ratios.get(key);
			double  freq_q=0.0;
			
			if(unigrams.nodes.containsKey(key)){
				
				freq_q= unigrams.nodes.get(key).getProb();
			}
					
			double freq_t=0.0;
			
			if(unigrams.nodes.containsKey(tag)){
				
				freq_t= unigrams.nodes.get(tag).getProb();
			} 
			
			double qt= getCoOccuranceFreq(key,tag);
			
			
			double temporal= 0;
			if(freq_t>0){
				
				temporal=ratio* qt/freq_t;
			}
			
			similarity +=temporal;
			
			
			
		}
		
		
		return similarity;
		
	}
	
	
	
	private double calculateChildrenProb(String tag) {
		// TODO Auto-generated method stub
		
		double score=0.0;
		for(int i=0; i<Constants.kids_seeds.length; i++){
			
			String kid_seed= Constants.kids_seeds[i];
			float freq_s=0;
			if(unigrams.nodes.containsKey(kid_seed)){
				
				freq_s= unigrams.nodes.get(kid_seed).getProb();
			}
			float freq_tag=0;
			if(unigrams.nodes.containsKey(tag)){
				
				freq_tag= unigrams.nodes.get(tag).getProb();
			}
					
			
			
			double qt= getCoOccuranceFreq(kid_seed,tag);
			
			
			if(freq_s!=0){
				score = score + (double)qt/(double)freq_s;
				
			}
			
		}
		
		return score;		
	}
	
	
	private double calculateChildrenDistance(String tag) {
		// TODO Auto-generated method stub
		
		double score=0.0;
		for(int i=0; i<Constants.kids_seeds.length; i++){
			
			String kid_seed= Constants.kids_seeds[i];
			float freq_s=0;
			if(unigrams.nodes.containsKey(kid_seed)){
				
				freq_s= unigrams.nodes.get(kid_seed).getProb();
			}
			float freq_tag=0;
			if(unigrams.nodes.containsKey(tag)){
				
				freq_tag= unigrams.nodes.get(tag).getProb();
			}
					
			
			
			double qt= getCoOccuranceFreq(kid_seed,tag);
			freq_tag+=1;
			freq_s+=1;
			qt+=1;
			
			double temporal=getGoogleDistance( freq_tag,freq_s,  qt);
			
			score+=temporal;
			
			
		}
		
		return score;		
	}
	
	
	private double calcualteLMAdults(Hashtable<String, Float> query_ratios, String tag) {
		// TODO Auto-generated method stub
		
		
		Enumeration<String> keys = query_ratios.keys();
		
		double similarity=0;
		while(keys.hasMoreElements()){
			
			String key=keys.nextElement();
			float ratio=query_ratios.get(key);
			double  freq_q=0.0;
			
			if(unigrams.nodes.containsKey(key)){
				
				freq_q= unigrams.nodes.get(key).getProb_adults();
			}
					
			double freq_t=0.0;
			
			if(unigrams.nodes.containsKey(tag)){
				
				freq_t= unigrams.nodes.get(tag).getProb_adults();
			} 
			
			double qt= getCoOccuranceFreq(key,tag);
			
			
			double temporal= 0;
			if(freq_t>0){
				
				temporal=ratio* qt/freq_t;
			}
			
			similarity +=temporal;
			
			
			
		}
		
		
		return similarity;
		
	}
	
	
	
	private double calcualteJaccardDistance(Hashtable<String, Float> query_ratios, String tag) {
		// TODO Auto-generated method stub
		
		
		Enumeration<String> keys = query_ratios.keys();
	
		
		double similarity=0;
		while(keys.hasMoreElements()){
			
			String key=keys.nextElement();
			float ratio=query_ratios.get(key);
			double  freq_q=0.0;
			
			if(unigrams.nodes.containsKey(key)){
				
				freq_q= unigrams.nodes.get(key).getProb();
			}
					
			double freq_t=0.0;
			
			if(unigrams.nodes.containsKey(tag)){
				
				freq_t= unigrams.nodes.get(tag).getProb();
			} 
			
			double qt= getCoOccuranceFreq(key,tag);
			
			
			double temporal= 0;
			if(freq_q>0){
				double a_u_b= freq_t+ freq_q;
				double jaccard = 1-((a_u_b-qt)/(a_u_b));
				temporal=ratio* jaccard;
			}
			
			similarity +=temporal;
			
			
			
		}

		return similarity;
		
	}
	
	
	private double calcualteGoogleDistance(Hashtable<String, Float> query_ratios, String tag) {
		// TODO Auto-generated method stub
		
		
		Enumeration<String> keys = query_ratios.keys();
		
		double similarity=0;
		while(keys.hasMoreElements()){
			
			String key=keys.nextElement();
			float ratio=query_ratios.get(key);
			double  freq_q=0.0;
			
			if(unigrams.nodes.containsKey(key)){
				
				freq_q= unigrams.nodes.get(key).getProb();
			}
					
			double freq_t=0.0;
			
			if(unigrams.nodes.containsKey(tag)){
				
				freq_t= unigrams.nodes.get(tag).getProb();
			} 
			
			double qt= getCoOccuranceFreq(tag,key);
			freq_q+=1;
			freq_t+=1;
			qt+=1;
			
			double temporal=getGoogleDistance( freq_t,freq_q,  qt);
			
		
			similarity +=ratio*temporal;
			
			
			
		}
		
	
		return similarity;
		
	}
	
	
	private double calcualteGoogleDistanceAdults(Hashtable<String, Float> query_ratios, String tag) {
		// TODO Auto-generated method stub
		
		
		Enumeration<String> keys = query_ratios.keys();
		
		double similarity=0;
		while(keys.hasMoreElements()){
			
			String key=keys.nextElement();
			float ratio=query_ratios.get(key);
			double  freq_q=0.0;
			
			if(unigrams.nodes.containsKey(key)){
				
				freq_q= unigrams.nodes.get(key).getProb_adults();
			}
					
			double freq_t=0.0;
			
			if(unigrams.nodes.containsKey(tag)){
				
				freq_t= unigrams.nodes.get(tag).getProb_adults();
			} 
			
			double qt= getCoOccuranceFreq(tag,key);
			freq_q+=1;
			freq_t+=1;
			qt+=1;
			
			double temporal=getGoogleDistance( freq_t,freq_q,  qt);
			
		
			similarity +=ratio*temporal;
			
			
			
		}
		
	
		return similarity;
		
	}
	
	public double getGoogleDistance(double freq_t, double freq_q, double qt){
		
		
		double max= Math.max(Math.log(freq_t), Math.log(freq_q));
		double min= Math.max(Math.log(freq_t), Math.log(freq_q));
		 qt= Math.log(qt);
		double m= Math.log(Constants.TOTAL_URL_KIDS);
		return (max-qt)/(m-min);
	}


	public double getCoOccuranceFreq(String aa, String bb) {

		int freq = 0;

		
		if (lm.lm.containsKey(aa)) {

			 Hashtable<String, DeliciousEdgeSimple> temp = lm.lm.get(aa);

			if (temp.containsKey(bb)) {

				freq += agg.getAggregate(temp.get(bb).freq);
			}
		} else if (lm.lm.containsKey(bb)) {

			 Hashtable<String, DeliciousEdgeSimple> temp  = lm.lm.get(bb);
			if (temp.containsKey(aa)) {
				freq += agg.getAggregate(temp.get(aa).freq);

			}
		}

		return freq;
	}
	
	
	
	
	
public Hashtable<String,Float> calculateQueryRatios(ArrayList<QueryTag>q){
		
		Hashtable<String, Float> qq= new Hashtable<String, Float> ();
		double total=0;
		if(q==null) return qq;
		
		
		for(int i =0; q!=null&& i<q.size();i++){
			QueryTag element = q.get(i);
			 total =total+ element.freq;
		}
		for(int i =0; i<q.size();i++){
			QueryTag element = q.get(i);
			 total =total+ element.freq;
			 
			 if (element.freq>=query_threshold_freq){
					//	if(tag.equals("characterized")){System.out.println("aqui si estuvo characterizeds " );}
						qq.put(element.tag, (float)((float)element.freq/total));		
			}
			 
		}
		
//		System.out.println( q+"\t"+ qq);
		return qq;
	}	
	public static void main(String argvs[]) {

		String prefix = "/Users/sergioduarte/projects/data/graph/";

		String path = "../data/graph/plus/graph_plus_youth.txt";
		//static String path = "../data/graph/last/samplet.txt";
		String node_node = "../data/graph/plus/tags_bigrams_plus_youth.txt";
		String query_tags = "/home/sergio/data/graph/query_tags_plus1.txt";
		HashSet<String>ages= new HashSet<String>();
		
		String features="/home/sergio/projects/learning_rank/query_suggestions/models/big_feature_file_clean.txt";
		features="/home/sergio/projects/learning_rank/query_suggestions/models/ranklib/rw_kl_features_10_12txt";
		
		if(argvs.length>1){
			
			path= argvs[0];
			node_node= argvs[1];
			query_tags= argvs[2];
			features=argvs[3];
			ages.add(argvs[4]);
			if(argvs.length>5){
				
				ages.add(argvs[5]);
				
				if(argvs.length>6){
					
					ages.add(argvs[6]);
				}
			}
			
			
		}else{
			
			ages.add("kids-teens");
		}
		
	//String age="teens-mteens";
		
		
		//ages.add(age);
		//ages.add("kids-teen-mteens");
	
		
		TagSimilarity sim= new TagSimilarity(path, node_node, query_tags,features,ages);
		sim.print_tag_similarity_features();
	}
	


}


